home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Tools - Objects / C++ / MPW C++ 3.1b1 / Examples / CPlusExamples / TApplication.cp < prev    next >
Text File  |  1989-09-29  |  10KB  |  412 lines

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple Application Framework
  6. #
  7. #    CPlusAppLib
  8. #
  9. #    TApplication.cp        -    C++ source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.10                     07/89
  16. #            1.00                     04/89
  17. #
  18. #    Components:
  19. #            TApplicationCommon.h    July 9, 1989
  20. #            TApplication.h            July 9, 1989
  21. #            TDocument.h                July 9, 1989
  22. #            TApplication.cp            July 9, 1989
  23. #            TDocument.cp            July 9, 1989
  24. #            TApplication.r            July 9, 1989
  25. #
  26. #    CPlusAppLib is a rudimentary application framework
  27. #    for C++. The applications CPlusShapesApp and CPlusTESample
  28. #    are built using CPlusAppLib.
  29. #
  30. ------------------------------------------------------------------------------*/
  31.  
  32.  
  33. /*
  34. Segmentation strategy:
  35.  
  36.     This program has only one segment, since the issues
  37.     surrounding segmentation within a class's methods have
  38.     not been investigated yet. We DO unload the data
  39.     initialization segment at startup time, which frees up
  40.     some memory 
  41.  
  42. SetPort strategy:
  43.  
  44.     Toolbox routines do not change the current port. In
  45.     spite of this, in this program we use a strategy of
  46.     calling SetPort whenever we want to draw or make calls
  47.     which depend on the current port. This makes us less
  48.     vulnerable to bugs in other software which might alter
  49.     the current port (such as the bug (feature?) in many
  50.     desk accessories which change the port on OpenDeskAcc).
  51.     Hopefully, this also makes the routines from this
  52.     program more self-contained, since they don't depend on
  53.     the current port setting. 
  54.  
  55. Clipboard strategy:
  56.  
  57.     This program does not maintain a private scrap.
  58.     Whenever a cut, copy, or paste occurs, we import/export
  59.     from the public scrap to TextEdit's scrap right away,
  60.     using the TEToScrap and TEFromScrap routines. If we did
  61.     use a private scrap, the import/export would be in the
  62.     activate/deactivate event and suspend/resume event
  63.     routines. 
  64. */
  65.  
  66. // Mac Includes
  67. #include <Types.h>
  68. #include <QuickDraw.h>
  69. #include <Fonts.h>
  70. #include <Events.h>
  71. #include <Controls.h>
  72. #include <Windows.h>
  73. #include <Menus.h>
  74. #include <TextEdit.h>
  75. #include <Dialogs.h>
  76. #include <Desk.h>
  77. #include <Scrap.h>
  78. #include <ToolUtils.h>
  79. #include <Memory.h>
  80. #include <SegLoad.h>
  81. #include <Files.h>
  82. #include <OSUtils.h>
  83. #include <Traps.h>
  84.  
  85. #include "TApplication.h"
  86.  
  87. // OSEvent is the event number of the suspend/resume and mouse-moved events sent
  88. // by MultiFinder. Once we determine that an event is an osEvent, we look at the
  89. // high byte of the message sent to determine which kind it is. To differentiate
  90. // suspend and resume events we check the resumeMask bit.
  91. const short kOsEvent = app4Evt;                // event used by MultiFinder
  92. const short kSuspendResumeMessage = 0x01;    // high byte of suspend/resume event message
  93. const short kClipConvertMask = 0x02;        // bit of message field clip conversion
  94. const short kResumeMask = 0x01;                // bit of message field for resume vs. suspend
  95. const short kMouseMovedMessage = 0xFA;        // high byte of mouse-moved event message
  96.  
  97. extern "C" { 
  98.     // from MPW standard library
  99.     void _DataInit(void);                // sets up A5 globals
  100. };
  101.  
  102. TApplication::TApplication(void)
  103. {
  104.     SysEnvRec envRec;
  105.     long stkNeeded, heapSize;
  106.  
  107.     // initialize Mac Toolbox components
  108.     InitGraf((Ptr) &qd.thePort);
  109.     InitFonts();
  110.     InitWindows();
  111.     InitMenus();
  112.     TEInit();
  113.     InitDialogs((ResumeProcPtr) nil);
  114.     InitCursor();
  115.  
  116.     // Unload data segment: note that _DataInit must not be in Main!
  117.     UnloadSeg((ProcPtr) _DataInit);
  118.  
  119.     // ignore the error returned from SysEnvirons; even if an error occurred,
  120.     // the SysEnvirons glue will fill in the SysEnvRec
  121.     (void) SysEnvirons(curSysEnvVers, &envRec);
  122.  
  123.     // Are we running on a 128K ROM machine or better???
  124.     if (envRec.machineType < 0)
  125.       BigBadError(kErrStrings,eWrongMachine);        // if not, alert & quit
  126.  
  127.     // if we need more stack space, get it now
  128.     stkNeeded = StackNeeded();
  129.     if (stkNeeded > StackSpace())
  130.       {
  131.         // new address is heap size + current stack - needed stack
  132.         SetApplLimit((Ptr) ((long) GetApplLimit() - stkNeeded + StackSpace()));
  133.       }
  134.  
  135.     // Check for minimum heap size
  136.     heapSize = (long) GetApplLimit() - (long) ApplicZone();
  137.     if (heapSize < HeapNeeded())
  138.       BigBadError(kErrStrings,eSmallSize);
  139.  
  140.     // expand the heap so new code segments load at the top
  141.     MaxApplZone();
  142.  
  143.     // allocate an empty document list
  144.     fDocList = new TDocumentList;
  145.  
  146.     // check to see if WaitNextEvent is implemented
  147.     fHaveWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
  148.  
  149.     // initialize our class variables
  150.     fCurDoc = nil;
  151.     fDone = false;
  152.     fInBackground = false;
  153.     fMouseRgn = nil;
  154.     fWhichWindow = nil;
  155. }
  156.  
  157. void TApplication::ExitLoop(void)
  158. {
  159.     fDone = true;
  160. }
  161.  
  162. void TApplication::EventLoop(void)
  163. {
  164.     int gotEvent;
  165.     EventRecord tEvt;
  166.  
  167.     SetUp();                    // call setup routine
  168.     DoIdle();                    // do idle once
  169.  
  170.     while (fDone == false)
  171.       {
  172.         // always set up fWhichWindow before doing anything
  173.         fWhichWindow = FrontWindow();
  174.         // see if window belongs to a document
  175.         fCurDoc = fDocList->FindDoc(fWhichWindow);
  176.         // make sure we always draw into correct window
  177.         SetPort(fWhichWindow);
  178.  
  179.         DoIdle();            // call idle time handler
  180.         
  181.         if (fHaveWaitNextEvent)
  182.           {
  183.             gotEvent = WaitNextEvent(everyEvent, &tEvt, SleepVal(), fMouseRgn);
  184.           }
  185.         else
  186.           {
  187.             SystemTask();
  188.             gotEvent = GetNextEvent(everyEvent, &tEvt);
  189.           }
  190.         fTheEvent = tEvt;
  191.  
  192.         // make sure we got a real event
  193.         if ( gotEvent )
  194.           {
  195.             AdjustCursor();
  196.             switch (fTheEvent.what)
  197.               {
  198.                 case mouseDown :
  199.                     DoMouseDown();
  200.                     break;
  201.                 case mouseUp :
  202.                     DoMouseUp();
  203.                     break;
  204.                 case keyDown :
  205.                 case autoKey :
  206.                     DoKeyDown();
  207.                     break;
  208.                 case updateEvt :
  209.                     DoUpdateEvt();                
  210.                     break;
  211.                 case diskEvt :
  212.                     DoDiskEvt();
  213.                     break;
  214.                 case activateEvt :
  215.                     DoActivateEvt();
  216.                     break;
  217.                 case kOsEvent :
  218.                     DoOSEvent();
  219.                     break;
  220.                 default :
  221.                     break;
  222.               } // end switch (fTheEvent.what)
  223.           }
  224.         AdjustCursor();
  225.       }
  226.     // call cleanup handler
  227.     CleanUp();
  228. }
  229.  
  230. void TApplication::DoKeyDown(void)
  231. {
  232.     char key;
  233.     long mResult;
  234.  
  235.     key = (char) (fTheEvent.message & charCodeMask);
  236.     if ((fTheEvent.modifiers & cmdKey) && (fTheEvent.what == keyDown))
  237.       {
  238.         // only do command keys if we are not autokeying
  239.         AdjustMenus();                    // make sure menus are up to date
  240.         mResult = MenuKey(key);
  241.         if (mResult != 0)                // if it wasn't a menu key, pass it through
  242.           {
  243.             DoMenuCommand(HiWrd(mResult), LoWrd(mResult));
  244.             return;
  245.           }
  246.       }
  247.     if (fCurDoc != nil)
  248.       {
  249.         EventRecord tEvt;
  250.  
  251.         // we copy event record so that we don't pass reference to object field 
  252.         tEvt = fTheEvent;
  253.         fCurDoc->DoKeyDown(&tEvt);
  254.       }
  255. }
  256.  
  257. void TApplication::DoActivateEvt(void)
  258. {
  259.     // event record contains window ptr
  260.     fWhichWindow = (WindowPtr) fTheEvent.message;
  261.     // see if window belongs to a document
  262.     fCurDoc = fDocList->FindDoc(fWhichWindow);
  263.     SetPort(fWhichWindow);
  264.  
  265.     if (fCurDoc != nil)
  266.       fCurDoc->DoActivate((fTheEvent.modifiers & activeFlag) != 0);
  267. }
  268.  
  269. void TApplication::DoUpdateEvt(void)
  270. {
  271.     // event record contains window ptr
  272.     fWhichWindow = (WindowPtr) fTheEvent.message;
  273.     // see if window belongs to a document
  274.     fCurDoc = fDocList->FindDoc(fWhichWindow);
  275.     SetPort(fWhichWindow);
  276.  
  277.     if (fCurDoc != nil)
  278.       fCurDoc->DoUpdate();
  279. }
  280.  
  281. void TApplication::DoSuspend(Boolean doClipConvert)
  282. {
  283.     doClipConvert = false;        // this is here because I HATE compiler warnings!!
  284.     if (fCurDoc != nil)
  285.       fCurDoc->DoActivate(!fInBackground);
  286. }
  287.  
  288. void TApplication::DoResume(Boolean doClipConvert)
  289. {
  290.     doClipConvert = false;        // this is here because I HATE compiler warnings!!
  291.     if (fCurDoc != nil)
  292.       fCurDoc->DoActivate(!fInBackground);
  293. }
  294.  
  295. void TApplication::DoOSEvent(void)
  296. {
  297.     Boolean doConvert;
  298.     unsigned char evType;
  299.  
  300.     // is it a multifinder event?
  301.     evType = (unsigned char) (fTheEvent.message >> 24) & 0x00ff;
  302.     switch (evType) {     // high byte of message is type of event
  303.         case kMouseMovedMessage :
  304.             DoIdle();                    // mouse-moved is also an idle event
  305.             break;
  306.         case kSuspendResumeMessage :
  307.             doConvert = (fTheEvent.message & kClipConvertMask) != 0;
  308.             fInBackground = (fTheEvent.message & kResumeMask) == 0;
  309.             if (fInBackground)
  310.               DoSuspend(doConvert);
  311.             else DoResume(doConvert);
  312.             break;
  313.     }
  314. }
  315.  
  316. void TApplication::DoMouseDown(void)
  317. {
  318.     long mResult;
  319.     short partCode;
  320.     WindowPtr tWind;
  321.     EventRecord tEvt;
  322.  
  323.     // gotta watch those object field dereferences
  324.     partCode = FindWindow(fTheEvent.where, &tWind);
  325.     fWhichWindow = tWind;
  326.     tEvt = fTheEvent;
  327.     switch (partCode)
  328.       {
  329.         case inSysWindow :
  330.             DoMouseInSysWindow();
  331.             break;
  332.         case inMenuBar :
  333.             AdjustMenus();
  334.             mResult = MenuSelect(tEvt.where);
  335.             if (mResult != 0)
  336.               DoMenuCommand(HiWrd(mResult),LoWrd(mResult));
  337.             break;
  338.         case inGoAway :
  339.             DoGoAway();                    
  340.             break;
  341.         case inDrag :
  342.             DoDrag();
  343.             break;
  344.         case inGrow :
  345.             if (fCurDoc != nil)
  346.               fCurDoc->DoGrow(&tEvt);                    
  347.             break;
  348.         case inZoomIn :
  349.         case inZoomOut :
  350.             if ((TrackBox(fWhichWindow, tEvt.where, partCode)) &&
  351.                 (fCurDoc != nil))
  352.               fCurDoc->DoZoom(partCode);
  353.             break;
  354.         case inContent :
  355.             // If window is not in front, make it so
  356.             if ( fWhichWindow != FrontWindow() )
  357.               SelectWindow(fWhichWindow);
  358.             else if (fCurDoc != nil)
  359.               fCurDoc->DoContent(&tEvt);                    
  360.             break;
  361.       }
  362. }
  363.  
  364. void TApplication::DoDrag(void)
  365. {
  366.     DragWindow(fWhichWindow, fTheEvent.where, &qd.screenBits.bounds);
  367. }
  368.  
  369. void TApplication::DoGoAway(void)
  370. {
  371.     if (TrackGoAway(fWhichWindow, fTheEvent.where))
  372.       {
  373.         if (fCurDoc != nil)
  374.           {
  375.             fDocList->RemoveDoc(fCurDoc);
  376.             fCurDoc->DoClose();
  377.           }
  378.         else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind);
  379.         // make sure our current document/window references are valid
  380.         if (fWhichWindow != nil)
  381.           {
  382.             fCurDoc = fDocList->FindDoc(fWhichWindow);
  383.             SetPort(fWhichWindow);
  384.           }
  385.         else fCurDoc = nil;
  386.       }
  387. }
  388.  
  389. Boolean TApplication::TrapAvailable(short tNumber,TrapType tType)
  390. {
  391.     // Check and see if the trap exists. On 64K ROM machines, tType will be ignored.
  392.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  393. } /*TrapAvailable*/
  394.  
  395. void AlertUser(short errResID, short errCode)
  396. {
  397.     Str255 message;
  398.  
  399.     SetCursor(&qd.arrow);
  400.     GetIndString(message, errResID, errCode);
  401.     ParamText(message, "\p", "\p", "\p");
  402.     (void) Alert(rUserAlert, (ModalFilterProcPtr) nil);
  403. } // AlertUser
  404.  
  405. void BigBadError(short errResID, short errCode)
  406. {
  407.     AlertUser(errResID,errCode);
  408.     ExitToShell();
  409. }
  410.  
  411. // That's all, folks...
  412.